package lucene.server.database.meta;

import lucene.server.common.utils.TypeUtil;
import lucene.server.database.model.ColumnModel;
import lucene.server.database.model.DatabaseModel;
import lucene.server.database.model.TableModel;
import lucene.server.database.utils.DatabaseUtil;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

public class AbstractDialect  implements IDialectMeta{

    protected String databaseType;
    public AbstractDialect(String databaseType){
        this.databaseType = databaseType;
    }

    @Override
    public Map<String,DatabaseModel> getDataBases(Connection connection) {
        Map<String,DatabaseModel> databaseModels = new HashMap<>();
        ResultSet catalogs = null;
        try {
            catalogs = connection.getMetaData().getCatalogs();
            while (catalogs.next()) {
                DatabaseModel databaseModel = new DatabaseModel();
                databaseModel.setCatalog(catalogs.getString("TABLE_CAT"));
                databaseModel.setName(catalogs.getString("TABLE_CAT"));
                databaseModel.setSchema("");
                databaseModel.setType(databaseType);
                databaseModels.put(databaseModel.getName(),databaseModel);
            }
            catalogs.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            DatabaseUtil.close(connection,catalogs);
        }
        return databaseModels;
    }


    @Override
    public void setTables(Connection connection,DatabaseModel databaseModel) {
        ResultSet tables = null;
        try {
            DatabaseMetaData metaData = connection.getMetaData();
            tables = metaData.getTables(databaseModel.getCatalog(), databaseModel.getSchema(), null, new String[]{"TABLE"});
            while (tables.next()) {
                TableModel tableModel = new TableModel();
                tableModel.setCatalog(databaseModel.getCatalog());
                tableModel.setSchema(databaseModel.getSchema());
                tableModel.setTableName(tables.getString("TABLE_NAME"));
                tableModel.setComment(tables.getString("REMARKS"));
                databaseModel.getTableMap().put(tableModel.getTableName(),tableModel);
            }
            databaseModel.getTableMap().values().forEach(tableModel -> {
                setPrimaryKeys(connection,databaseModel,tableModel);
            });
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            DatabaseUtil.close(connection,tables);
        }
    }

    @Override
    public void setColumns(Connection connection, DatabaseModel databaseModel, TableModel tableModel) {
        ResultSet resultSet = null;
        try {

            DatabaseMetaData metaData = connection.getMetaData();
            resultSet = metaData.getColumns(tableModel.getCatalog(), tableModel.getSchema(), tableModel.getTableName(), null);

            while (resultSet.next()) {
                ColumnModel columnModel = new ColumnModel();
                columnModel.setTableCat(tableModel.getCatalog());
                columnModel.setTableSchem(tableModel.getSchema());
                columnModel.setTableName(tableModel.getTableName());
                columnModel.setDataType(resultSet.getInt("DATA_TYPE"));
                try {
                    columnModel.setTypeName(TypeUtil.SQLTypeToJavaType(resultSet.getInt("DATA_TYPE")).getSimpleName());
                }catch (Exception e){
                    System.out.println("Unsupported SQL type:"+resultSet.getString("COLUMN_NAME")+",TYPE_NAME:" +resultSet.getString("TYPE_NAME") +",DATA_TYPE"+ resultSet.getInt("DATA_TYPE"));
                }
                columnModel.setColumnName(resultSet.getString("COLUMN_NAME"));
                columnModel.setColumnIndex( resultSet.getInt("ORDINAL_POSITION")-1);
                columnModel.setOriginalType(resultSet.getString("TYPE_NAME"));
                columnModel.setColumnRemark(resultSet.getString("REMARKS"));
                columnModel.setColumnSize(resultSet.getString("COLUMN_SIZE"));
                columnModel.isBinaryType = TypeUtil.isBinaryColumn(resultSet.getInt("DATA_TYPE")) ;
                columnModel.isStringType = TypeUtil.isStringColumn(resultSet.getInt("DATA_TYPE"));
                columnModel.isDateTimeType = TypeUtil.isDatetimeColumn(resultSet.getString("TYPE_NAME"));
                tableModel.getColumnsMap().add(columnModel);
            }

        }catch (SQLException e){
            throw new RuntimeException(e);
        }finally {
            DatabaseUtil.close(resultSet,connection);
        }
    }

    @Override
    public void setPrimaryKeys(Connection connection, DatabaseModel databaseModel, TableModel tableModel) {
        ResultSet primaryKeys = null;
        try {
            primaryKeys = connection.getMetaData().getPrimaryKeys(tableModel.getCatalog(), tableModel.getSchema(), tableModel.getTableName());
            while (primaryKeys.next()) {
                tableModel.getPrimaryKeys().add(primaryKeys.getString("COLUMN_NAME"));
            }
            primaryKeys.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            DatabaseUtil.close(primaryKeys);
        }
    }
}
